package com.qijia.common.dao.impl;

import java.math.BigInteger;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

import org.springframework.dao.DataAccessException;
import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport;

import com.ibatis.sqlmap.client.SqlMapClient;
import com.qijia.common.dao.BaseDao;
import com.qijia.common.domain.BaseData;
import com.qijia.common.domain.example.BaseCriteria;
import com.qijia.common.domain.example.BaseExample;
import com.qijia.common.utils.PageUtil;

/**
 * 数据库基本操作Dao实现，ibatis版本
 * @author Administrator
 *
 * @param <T>
 */
public class IbatisUtilsDaoImpl<T extends BaseData> extends
		SqlMapClientDaoSupport implements BaseDao<T> {

	T t;

	private String getTName() {
		return t.getClass().getSimpleName();
	}

	@Resource(name = "sqlMapClient")
	private SqlMapClient sqlMapClient;

	@PostConstruct
	public void initSqlMapClient() {
		super.setSqlMapClient(sqlMapClient);
	}

	public SqlMapClient getSqlClient() {
		return this.getSqlMapClient();
	}

	public int countByExample(BaseExample example) {
		return countByExample(SqlMapConstants.COUNT_BY_EXAMPLE, example);
	}

	public int countByExample(String mappedId, Object example) {
		try {
			return (Integer) getSqlMapClientTemplate().queryForObject(
					getTName() + mappedId, example);
		} catch (DataAccessException e) {
			throw new DbException(getTName() + mappedId, example, e);
		}
	}

	public int delByExampleSelective(BaseExample example) {
		try {
			return getSqlMapClientTemplate().delete(
					getTName() + SqlMapConstants.DELETE_BY_EXAMPLE, example);
		} catch (DataAccessException e) {
			throw new DbException(getTName() + SqlMapConstants.DELETE_BY_EXAMPLE, example, e);
		}
	}

	@SuppressWarnings("unchecked")
	public void delByPrimaryKey(Object key) {
		try {
			t = (T) t.getClass().newInstance();
			t.setPkKey(key);
			getSqlMapClientTemplate().delete(
					getTName() + SqlMapConstants.DELETE_BY_PRIMARY_KEY, t);
		} catch (DataAccessException e) {
			throw new DbException(getTName() + SqlMapConstants.DELETE_BY_PRIMARY_KEY, key, e);
		} catch (Exception e) {
			throw new DbException(getTName() + SqlMapConstants.DELETE_BY_PRIMARY_KEY, t, e);
		}
	}

	public T getLastObjectByExample(BaseExample example) {
		example.setOrderByClause(" createTime desc ");
		List<T> ts = this.selectByExample(example);
		if (null == ts || ts.size() <= 0)
			return null;
		else
			return ts.get(0);
	}

	@SuppressWarnings("unchecked")
	public T getObjectByKey(Object key) {
		try {
			t = (T) t.getClass().newInstance();
			t.setPkKey(key);
			return (T) getSqlMapClientTemplate().queryForObject(
					getTName() + SqlMapConstants.SELECT_BY_PRIMARY_KEY, t);
		} catch (DataAccessException e) {
			throw new DbException(getTName() + SqlMapConstants.SELECT_BY_PRIMARY_KEY, key, e);
		} catch (Exception e) {
			throw new DbException(getTName() + SqlMapConstants.SELECT_BY_PRIMARY_KEY, t, e);
		}
	}

	@SuppressWarnings("unchecked")
	public Object getPkKey() {
		Map<String, Object> dataMap;
		try {
			dataMap = (Map<String, Object>) sqlMapClient.queryForObject(
					SqlMapConstants.SELECT_TABLE_STATUS, getTName());
			Object id = dataMap.get(SqlMapConstants.AUTO_INCREMENT_CODE);
			if (id instanceof Long)
				return (Long) id;
			else if (id instanceof BigInteger)
				return ((BigInteger) id).longValue();
			else if (id instanceof Integer)
				return Long.valueOf(((Integer) id));
			else
				return (long) 0;
		} catch (SQLException e) {
			throw new DbException(SqlMapConstants.SELECT_TABLE_STATUS, e);
		}
	}

	public void mutiDel(List<Object> keys) {
		for (Object key : keys) {
			try {
				this.delByPrimaryKey(key);
			} catch (DbException e) {
				continue;
			}
		}
	}

	public List<Object> mutiSave(List<T> t) {
		List<Object> ts = new ArrayList<Object>();
		for (T key : t) {
			try {
				this.save(key);
			} catch (DbException e) {
				continue;
			}
		}
		return ts;
	}

	public void save(T t) {
		try {
			Object key = this.getPkKey();
			t.setPkKey(key);
			getSqlMapClientTemplate().insert(getTName() + SqlMapConstants.INSERT, t);
		} catch (DataAccessException e) {
			throw new DbException(getTName() + SqlMapConstants.INSERT, t, e);
		}
	}

	@SuppressWarnings("unchecked")
	public List<T> selectByExample(BaseExample example) {
		return selectByExample(SqlMapConstants.SELECT_BY_EXAMPLE, example);
	}

	@SuppressWarnings("unchecked")
	public List<T> selectByExample(String mappId, Object example) {
		try {
			return getSqlMapClientTemplate().queryForList(getTName() + mappId,
					example);
		} catch (DataAccessException e) {
			throw new DbException(getTName() + SqlMapConstants.SELECT_BY_EXAMPLE, example, e);
		}
	}

	public PageUtil selectForPage(PageUtil page) {
		if (page == null) {
			throw new DbException("page parameter can not be null!");
		} else if (null == page.getCountMappedId()
				|| null == page.getSelectDataMappedId()) {
			throw new DbException("Mapped Id can not be null!");
		}
		try {
			page.setRowCnt(this.countByExample(getTName()
					+ page.getCountMappedId(), page.getSqlParamObj()));

			if (page.getSqlParamObj() instanceof BaseExample) {
				BaseExample example = (BaseExample) page.getSqlParamObj();
				example.setPageSize(page.getPageSize());
				example.setStartLine(page.getStartRow());
				page.setSqlParamObj(example);
			}
			page.setPageList(selectByExample(page.getSelectDataMappedId(), page
					.getSqlParamObj()));
			return page;
		} catch (DataAccessException e) {
			throw new DbException(page.getSelectDataMappedId() + "&&"
					+ page.getCountMappedId(), page, e);
		}
	}

	public int updateByExample(T record, BaseExample example) {
		UpdateByExampleParms<T> parms = new UpdateByExampleParms<T>(t, example);
		int rows = 0;
		try {
			rows = getSqlMapClientTemplate().update(
					getTName() + SqlMapConstants.UPDATE_BY_EXAMPLE, parms);
		} catch (DataAccessException e) {
			throw new DbException(getTName() + SqlMapConstants.UPDATE_BY_EXAMPLE, example, e);
		}
		return rows;
	}

	public int updateByPrimaryKey(T t) {
		try {
			return getSqlMapClientTemplate().update(
					getTName() + SqlMapConstants.UPDATE_BY_PRIMARY_KEY, t);
		} catch (DataAccessException e) {
			throw new DbException(getTName() + SqlMapConstants.UPDATE_BY_PRIMARY_KEY, t, e);
		}
	}

	public int updateByExampleSelective(T t, BaseExample example) {
		UpdateByExampleParms<T> parms = new UpdateByExampleParms<T>(t, example);
		int rows = 0;
		try {
			rows = getSqlMapClientTemplate().update(
					getTName() + SqlMapConstants.UPDATE_BY_EXAMPLE_SELECTIVE, parms);
		} catch (DataAccessException e) {
			throw new DbException(getTName() + SqlMapConstants.UPDATE_BY_EXAMPLE_SELECTIVE,
					example, e);
		}
		return rows;
	}

	public int updateByPrimaryKeySelective(T t) {
		try {
			return getSqlMapClientTemplate().update(
					getTName() + SqlMapConstants.UPDATE_BY_PRIMARY_KEY_SELECTIVE, t);
		} catch (DataAccessException e) {
			throw new DbException(getTName() + SqlMapConstants.UPDATE_BY_PRIMARY_KEY, t, e);
		}
	}

	private static class UpdateByExampleParms<T> extends BaseExample {
		private T record;

		public UpdateByExampleParms(T record, BaseExample example) {
			super(example);
			this.record = record;
		}

		public Object getRecord() {
			return record;
		}

		@Override
		protected BaseCriteria getCriteria() {
			return null;
		}
	}

}
